package cn.duhengkui.national.valuelist.core.data.impl;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import cn.duhengkui.national.valuelist.annotation.QueryObjCol;
import cn.duhengkui.national.valuelist.core.data.CommandExecutor;
import cn.duhengkui.national.valuelist.core.data.ExtendDao;
import cn.duhengkui.national.valuelist.core.data.StandardDao;
import cn.duhengkui.national.valuelist.core.data.exception.DAORunTimeException;
import cn.duhengkui.national.valuelist.core.data.util.DaoEntityThreadLocal;
import cn.duhengkui.national.valuelist.core.data.util.EntityAttribute;
import cn.duhengkui.national.valuelist.core.data.util.Entitys;
import cn.duhengkui.national.valuelist.core.data.util.ReflectUtil;
import cn.duhengkui.national.valuelist.core.entity.BaseEntity;
import cn.duhengkui.national.valuelist.core.entity.BaseQueryObject;
import cn.duhengkui.national.valuelist.core.entity.PaginatedResult;




/**   
 * <table border="1">
 *	<tr><td>包名称：</td><td>cn.duhengkui.national.valuelist.core.data.impl</td></tr>
 *	<tr><td>类名称：</td><td>BaseDaoImpl</td></tr>
 *	<tr><td>类描述：</td><td>Dao主实现类</td></tr>
 *	<tr><td>创建人：</td><td>杜恒奎</td></tr>
 *  <tr><td>创建时间：</td><td>2018年6月7日/下午3:54:01</td></tr> 
 *  <tr><td>版本：</td><td>1.0.0</td></tr>
 * </table>   
 *     
 */
public class BaseDaoImpl<Entity extends BaseEntity> implements StandardDao<Entity>,  ExtendDao<Entity>, CommandExecutor {
	

	protected JdbcTemplate jdbcTemplate;
	
	
	/*private Class<Entity> entityType;
	
	private Entitys entitys;*/
	
	private String dateSql;
	
	private String dateAlias;
	
	public void setDateSql(String dateSql) {
		this.dateSql = dateSql;
	}

	public void setDateAlias(String dateAlias) {
		this.dateAlias = dateAlias;
	}
	
	
	
	private JdbcTemplate getJdbcTemplate(){
		return jdbcTemplate;
	}
	
	
	/**
	 * @param entityType
	 *//*
	public  void entityType(Class<Entity> entityType, Entitys entitys) {
		this.entityType = entityType;
		this.entitys = entitys;
	}*/
	
	
	/**
	 * @param dataSource
	 */
	public @Resource void setDataSource(DataSource dataSource) {
		//this.dataSource = dataSource;
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	
	
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ReadOnlyDao#getDataBaseTime()
	 */
	public Date getDataBaseTime() {
		return new Date(getDataLong());
	}
	
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ReadOnlyDao#getDataBaseTimestamp()
	 */
	public Timestamp getDataBaseTimestamp() {
		return new Timestamp(getDataLong());
	}
	
	/**
	* @Title: getDataLong
	* @Description: 获取数据库时间
	* @return
	* @return long
	 * @throws SQLException 
	*/ 
	private long getDataLong() {
		
		//dataSourceRouting();
		Object object = getJdbcTemplate().queryForMap(dateSql).get(dateAlias);
		if(object instanceof Timestamp) {
			return ((Timestamp) object).getTime();
		} else if(object instanceof java.sql.Date) {
			return ((java.sql.Date) object).getTime();
		} else {
			return new Date().getTime();
		}
	}

	@Override
	public void load(Entity entity) {
		load(entity,false);
		
	}

	@Override
	public void loadForUpdate(Entity entity) {
		load(entity,true);
	}
	
	private final void load(final Entity entity,boolean forUpdate) {
		
		StringBuffer sql = new StringBuffer();
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		sql.append(entitys.createSelect());
		sql.append(" WHERE ");
		Map<String,EntityAttribute> keys = entitys.getPkMap();
		List<Object> values = new ArrayList<>();
		if (!keys.isEmpty()) {
			for (String name : keys.keySet()) {
				EntityAttribute attribute = keys.get(name);
				Object value = invokeGetMethod(entity, attribute.getterName());
				if(attribute.isPk() && value == null) {
					throw new DAORunTimeException("the column : " + attribute.getterName() + " must be not null.");
				}
				sql.append(keys.get(name).getName()).append("=? AND ");
				values.add(value);
			}
		} else {
			Map<String,Object> pks = entity.keys();
			for (String name : pks.keySet()) {
				sql.append(name).append("=? AND ");
				values.add(entity.key(name));
			}
		}
		String realSql = sql.substring(0, sql.length() - 5);
		if(forUpdate){
			realSql +=  " for update ";
		}
		entitys.setResult(getJdbcTemplate().queryForMap(realSql, values.toArray()), entity);
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.StandardDao#save(cn.duhengkui.national.valuelist.core.entity.BaseEntity)
	 */
	//@CachePut(value="entity")
	public final void save(final Entity entity) {
		//dataSourceRouting();
		final StringBuffer sql = new StringBuffer();
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		sql.append("INSERT INTO ").append(entitys.getName()).append(" (");
		List<EntityAttribute> list = entitys.getAttributeList();
		Map<String, EntityAttribute> pkMap = entitys.getPkMap();
		final List<Object> values = new ArrayList<>(list.size() - pkMap.size());
		StringBuffer questionMarks = new StringBuffer();
		for(EntityAttribute attribute : list) {
			if((attribute.isPk() && entitys.isIdentityPk()) || attribute.isNoInsert()) {
				continue;
			}
			sql.append(attribute.getName()).append(",");
			questionMarks.append("?,");
			if(attribute.isPk() && entitys.isUUIDPk()) {
				entitys.invokeSet(attribute.getName(), entity, getUUID());
			}
			Object value = invokeGetMethod(entity, attribute.getterName());
			if((attribute.isPk() || attribute.isNotNull()) && value == null) {
				throw new DAORunTimeException("the column : " + attribute.getterName() + " must be not null.");
			}
			values.add(value);
		}
		sql.delete(sql.lastIndexOf(Entitys.COLUMN_SPLIT), sql.lastIndexOf(Entitys.COLUMN_SPLIT) + 1);
		sql.append(") VALUES (");
		sql.append(questionMarks.toString());
		sql.delete(sql.lastIndexOf(Entitys.COLUMN_SPLIT), sql.lastIndexOf(Entitys.COLUMN_SPLIT) + 1);
		sql.append(")");
		KeyHolder keyHolder = new GeneratedKeyHolder();
		if (entitys.isIdentityPk()) {
			getJdbcTemplate().update(new PreparedStatementCreator() {
				@Override
				public PreparedStatement createPreparedStatement(Connection con)
						throws SQLException {
					PreparedStatement preparedStatement = con
							.prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS);
					int count = 0;
					for (Object obj : values) {
						preparedStatement.setObject(++count, obj);
					}
					return preparedStatement;
				}
			}, keyHolder);
			for(String name : pkMap.keySet()) {
				EntityAttribute attribute = pkMap.get(name);
				Object key = keyHolder.getKeys().get("GENERATED_KEY");
				entitys.invokeSet(attribute.getName(), entity, Integer.valueOf(key.toString()));
			}
		} else {
			getJdbcTemplate().update(sql.toString(), values.toArray());
		}
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.StandardDao#update(cn.duhengkui.national.valuelist.core.entity.BaseEntity)
	 */
	//@CachePut(value="entity")
	public final boolean update(Entity entity) {
		//dataSourceRouting();
		StringBuffer sql = new StringBuffer();
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		sql.append("UPDATE ").append(entitys.getName()).append(" SET ");
		List<EntityAttribute> list = entitys.getAttributeList();
		Map<String, EntityAttribute> pkMap = entitys.getPkMap();
		List<Object> values = new ArrayList<>(list.size() - pkMap.size());
		List<Object> pkValues = new ArrayList<>(pkMap.size());
		StringBuffer wheres = new StringBuffer();
		wheres.append(" WHERE ");
		for(EntityAttribute attribute : list) {
			if(attribute.isNoUpdate() && !attribute.isPk()) {
				continue;
			}
			Object value = invokeGetMethod(entity, attribute.getterName());
			if(attribute.isPk()) {
				pkValues.add(value);
				if(attribute.isPk() && value == null) {
					throw new DAORunTimeException("the column : " + attribute.getterName() + " must be not null.");
				}
				wheres.append(attribute.getName()).append("=? AND ");
			} else {
				if(attribute.isNotNull() && value == null) {
					throw new DAORunTimeException("the column : " + attribute.getterName() + " must be not null.");
				}
				values.add(value);
				sql.append(attribute.getName()).append("=?,");
			}
		}
		sql.delete(sql.lastIndexOf(Entitys.COLUMN_SPLIT), sql.lastIndexOf(Entitys.COLUMN_SPLIT) + 1);
		sql.append(wheres.toString());
		sql.delete(sql.lastIndexOf(" AND "), sql.lastIndexOf(" AND ") + 5);
		values.addAll(pkValues);
		int count = getJdbcTemplate().update(sql.toString(), values.toArray());
		return count == 1;
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.StandardDao#delete(cn.duhengkui.national.valuelist.core.entity.BaseEntity)
	 */
	//@CacheEvict(value="entity")
	public final boolean delete(Entity entity)
	{
		//dataSourceRouting();
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		StringBuffer sql = new StringBuffer();
		sql.append("DELETE FROM ").append(entitys.getName()).append(" WHERE ");
		Map<String, EntityAttribute> pkMap = entitys.getPkMap();
		List<Object> values = new ArrayList<>();
		for(String name : pkMap.keySet()) {
			EntityAttribute attribute = pkMap.get(name);
			sql.append(name).append("=? AND ");
			Object value = invokeGetMethod(entity, attribute.getterName());
			if(value == null) {
				throw new DAORunTimeException("the column : " + attribute.getterName() + "must be not null.");
			}
			values.add(value);
		}
		sql.delete(sql.lastIndexOf(" AND "), sql.lastIndexOf(" AND ") + 5);
		int count = getJdbcTemplate().update(sql.toString(), values.toArray());
		return count == 1;
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.StandardDao#saveOrUpdate(cn.duhengkui.national.valuelist.core.entity.BaseEntity)
	 */
	//@CachePut(value="entity")
	public final void saveOrUpdate(final Entity entity) {
		//dataSourceRouting();
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		Map<String, EntityAttribute> pkMap = entitys.getPkMap();
		boolean isInvokeUpdateMethod = true;
		for(String name : pkMap.keySet()) {
			EntityAttribute attribute = pkMap.get(name);
			Object pkValue = invokeGetMethod(entity, attribute.getterName());
			if((pkValue == null && (entitys.isUUIDPk() || entitys.isIdentityPk())) || (pkValue != null && !entitys.isUUIDPk() && !entitys.isIdentityPk())) {
				isInvokeUpdateMethod = false;
				break;
			}
			if(entitys.isUUIDPk() && pkValue.toString().length() != getUUID().length()) {
				isInvokeUpdateMethod = false;
			}
		}
		if(isInvokeUpdateMethod) {
			update(entity);
		} else {
			save(entity);
		}
	}
	

	/**
	* @Title: invokeGetMethod
	* @Description: 从entityType中执行get方法
	* @param entity
	* @param name
	* @return
	* @return Object
	*/ 
	private final Object invokeGetMethod(final Entity entity, String name) {
		Object obj;
		try {
			obj = DaoEntityThreadLocal.get().getMethod(name).invoke(entity);
		} catch (IllegalArgumentException 
				| SecurityException 
				| IllegalAccessException 
				| InvocationTargetException 
				| NoSuchMethodException e) {
			throw new DAORunTimeException(e);
		}
		return obj;
	}
	
	/**
	 * 创建一个新有实体对象
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected Entity newEntity() {
		Entity entity;
		try {
			entity = (Entity) DaoEntityThreadLocal.get().newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			throw new DAORunTimeException(e);
		}
		return entity;
	}
	
	
	/**
	 * 获取一个UUID字符串
	 * @return
	 */
	protected String getUUID() {
		return UUID.randomUUID().toString().replace("-", "");
	}
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#single(java.lang.String, java.lang.Object[])
	 */
	//@Cacheable(value="entity")
	public final Entity single(String sql, Object[] args) {
		//dataSourceRouting();
		Map<String, Object> result = getJdbcTemplate().queryForMap(sql, args);
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		Entity entity = newEntity();
		entitys.setResult(result, entity);
		return entity;
	}
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#single(java.lang.String, java.lang.Object[], java.lang.Class)
	 */
	//@Cacheable(value="entity")
	public final BaseQueryObject single(String sql, Object[] args, Class<? extends BaseQueryObject> qClazz){
		//dataSourceRouting();
		Map<String, Object> result = getJdbcTemplate().queryForMap(sql, args);
		try {
			BaseQueryObject entity = processMap(result,qClazz);
			return entity;
		} catch (ReflectiveOperationException e) {
			throw new DAORunTimeException(e);
		}
	}
	
	

	
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#batchUpdate(java.lang.String, java.util.List)
	 */
	//@CachePut(value="entity")
	public final int[] batchUpdate(String sql, List<Object[]> argsList) {
		//dataSourceRouting();
		return getJdbcTemplate().batchUpdate(sql, argsList);
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#batchRemove(java.lang.String, java.lang.Object[])
	 */
	//@CacheEvict(value="entity")
	public final int batchRemove(String sql, Object[] args) {
		//dataSourceRouting();
		return getJdbcTemplate().update(sql, args);
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#query(java.lang.String, java.lang.Object[])
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	//@Cacheable(value="entity")
	public final List<Entity> query(final String sql, final Object[] args) {
		//dataSourceRouting();
		final List<String> columnNames = new ArrayList<>(0);
		final List<Entity> list = new ArrayList<>();
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		getJdbcTemplate().query(new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				String sqlStatement = sql;
				PreparedStatement statement = con.prepareStatement(sqlStatement, ResultSet.TYPE_SCROLL_INSENSITIVE
						,ResultSet.CONCUR_READ_ONLY);
				for(int i = 0 ; i < args.length ; i++) {
					statement.setObject(i + 1, args[i]);
				}
				return statement;
			}
		}, new RowMapper() {
			boolean flag = true;
			public Object mapRow(ResultSet rs, int rowIndex) throws SQLException {
				if (flag) {
					flag = false;
					ResultSetMetaData rsmd = rs.getMetaData();
					int count = rsmd.getColumnCount();
					for (int i = 0; i < count; i++) {
						columnNames.add(rsmd.getColumnName(i + 1));
					}
				}
				Entity entity = newEntity();
				entitys.setResult(rs, columnNames, entity);
				list.add(entity);
				return Boolean.TRUE;
			}
		});
		return list;
	}
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#query(java.lang.String, java.lang.Object[], java.lang.Class)
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	//@Cacheable(value="entity")
	public final List<BaseQueryObject> query(final String sql, final Object[] args, Class<? extends BaseQueryObject> qClazz) {
		//dataSourceRouting();
		final List<String> columnNames = new ArrayList<>(0);
		final List<BaseQueryObject> list = new ArrayList<>();
		getJdbcTemplate().query(new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				String sqlStatement = sql;
				PreparedStatement statement = con.prepareStatement(sqlStatement, ResultSet.TYPE_SCROLL_INSENSITIVE
						,ResultSet.CONCUR_READ_ONLY);
				for(int i = 0 ; i < args.length ; i++) {
					statement.setObject(i + 1, args[i]);
				}
				return statement;
			}
		}, new RowMapper() {
			boolean flag = true;
			public Object mapRow(ResultSet rs, int rowIndex) throws SQLException {
				if (flag) {
					flag = false;
					ResultSetMetaData rsmd = rs.getMetaData();
					int count = rsmd.getColumnCount();
					for (int i = 0; i < count; i++) {
						columnNames.add(rsmd.getColumnName(i + 1));
					}
				}
				try {
					BaseQueryObject obj = processResultSet(rs,columnNames,qClazz);
					list.add(obj);
				} catch (InstantiationException | IllegalAccessException e) {
					throw new DAORunTimeException(e);
				}
				return Boolean.TRUE;
			}
		});
		return list;
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#query(java.lang.String, cn.duhengkui.national.valuelist.core.entity.PaginatedResult, java.lang.Object[])
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	//@Cacheable(value="entity")
	public final PaginatedResult<Entity> query(final String sql, final PaginatedResult<Entity> pr, final Object[] args) {
		//dataSourceRouting();
		int number = getJdbcTemplate().queryForObject("select count(getcount.*) from (" + sql + ") getcount", args, Integer.class);
		pr.setTotalSize(number);
		Entitys entitys = Entitys.newInstance(DaoEntityThreadLocal.get());
		final List<String> columnNames = new ArrayList<>(0);
		getJdbcTemplate().query(new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				String sqlStatement = sql;
				PreparedStatement statement = con.prepareStatement(sqlStatement,ResultSet.TYPE_SCROLL_INSENSITIVE
						,ResultSet.CONCUR_READ_ONLY);
				for(int i = 0 ; i < args.length ; i++) {
					statement.setObject(i + 1, args[i]);
				}
				return statement;
			}
		}, new RowMapper() {
			int rowCount = 0;
			int rsIndex;
			boolean flag = true;
			public Object mapRow(ResultSet rs, int rowIndex) throws SQLException {
				
				if(rowIndex == 0) {
					rs.last();
					rowCount = rs.getRow();
					if(rowCount >= pr.getStartPosition() + 1) {
						rsIndex = pr.getStartPosition() + 1;
					}
				}
				if((rowCount >= pr.getStartPosition() + rowIndex + 1) && rowIndex < pr.getPageSize() && rsIndex <= pr.getEndPosition())
					rs.absolute(rsIndex);
				else 
					return null;
				if (flag) {
					flag = false;
					ResultSetMetaData rsmd = rs.getMetaData();
					int count = rsmd.getColumnCount();
					for (int i = 0; i < count; i++) {
						columnNames.add(rsmd.getColumnName(i + 1));
					}
				}
					Entity entity = newEntity();
					entitys.setResult(rs, columnNames, entity);
					pr.addResult(entity);
				rsIndex++;
				return Boolean.TRUE;
			}
		});
		return pr;
	}

	
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#query(java.lang.String, cn.duhengkui.national.valuelist.core.entity.PaginatedResult, java.lang.Object[], java.lang.Class)
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	//@Cacheable(value="entity")
	public final PaginatedResult<BaseQueryObject> query(final String sql, final PaginatedResult<BaseQueryObject> pr, final Object[] args, Class<? extends BaseQueryObject> qClazz) {
		//dataSourceRouting();
		int number = getJdbcTemplate().queryForObject("select count(getcount.*) from (" + sql + ") getcount", args, Integer.class);
		pr.setTotalSize(number);
		final List<String> columnNames = new ArrayList<>(0);
		getJdbcTemplate().query(new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				String sqlStatement = sql;
				PreparedStatement statement = con.prepareStatement(sqlStatement,ResultSet.TYPE_SCROLL_INSENSITIVE
						,ResultSet.CONCUR_READ_ONLY);
				for(int i = 0 ; i < args.length ; i++) {
					statement.setObject(i + 1, args[i]);
				}
				return statement;
			}
		}, new RowMapper() {
			int rowCount = 0;
			int rsIndex;
			boolean flag = true;
			public Object mapRow(ResultSet rs, int rowIndex) throws SQLException {
				
				if(rowIndex == 0) {
					rs.last();
					rowCount = rs.getRow();
					if(rowCount >= pr.getStartPosition() + 1) {
						rsIndex = pr.getStartPosition() + 1;
					}
				}
				if((rowCount >= pr.getStartPosition() + rowIndex + 1) && rowIndex < pr.getPageSize() && rsIndex <= pr.getEndPosition())
					rs.absolute(rsIndex);
				else 
					return null;
				if (flag) {
					flag = false;
					ResultSetMetaData rsmd = rs.getMetaData();
					int count = rsmd.getColumnCount();
					for (int i = 0; i < count; i++) {
						columnNames.add(rsmd.getColumnName(i + 1));
					}
				}
				try {
					BaseQueryObject obj = processResultSet(rs,columnNames,qClazz);
					pr.addResult(obj);
				} catch (InstantiationException | IllegalAccessException e) {
					throw new DAORunTimeException(e);
				}
				rsIndex++;
				return Boolean.TRUE;
			}
		});
		return pr;
	}


	


	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.CommandExecutor#execute(java.lang.String)
	 */
	@Override
	public final void execute(String statement) {
		//dataSourceRouting();
		getJdbcTemplate().execute(statement);
	}
	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#queryFree(java.lang.String, java.lang.Object[])
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	//@Cacheable(value="entity")
	public final List<Map<String,Object>> queryFree(final String sql, final Object[] args) {
		//dataSourceRouting();
		final List<Map<String,Object>> list = new ArrayList<>();
		final List<String> columnNames = new ArrayList<>(0);
		getJdbcTemplate().query(new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				String sqlStatement = sql;
				PreparedStatement statement = con.prepareStatement(sqlStatement, ResultSet.TYPE_SCROLL_INSENSITIVE
						,ResultSet.CONCUR_READ_ONLY);
				for(int i = 0 ; i < args.length ; i++) {
					statement.setObject(i + 1, args[i]);
				}
				return statement;
			}
		}, new RowMapper() {
			boolean flag = true;
			public Object mapRow(ResultSet rs, int rowIndex) throws SQLException {
				if (flag) {
					flag = false;
					ResultSetMetaData rsmd = rs.getMetaData();
					int count = rsmd.getColumnCount();
					for (int i = 0; i < count; i++) {
						columnNames.add(rsmd.getColumnName(i + 1));
					}
				}
				Map<String,Object> freeMap = new HashMap<>();
				for (String key : columnNames) {
					freeMap.put(key, rs.getObject(key));
				}
				list.add(freeMap);
				
				return Boolean.TRUE;
			}
		});
		return list;
	}

	
	/* (non-Javadoc)
	 * @see cn.duhengkui.national.valuelist.core.data.ExtendDao#update(java.lang.String, java.lang.Object[])
	 */
	@Override
	public final int update(String sql, Object[] args) {
		//dataSourceRouting();
		return getJdbcTemplate().update(sql, args);
	}
	
	/**
	* @Title: processMap
	* @Description: 查询集（Map）反射到QO中
	* @param result
	* @param qClazz
	* @return
	* @throws ReflectiveOperationException
	* @return BaseQueryObject
	*/ 
	public final  BaseQueryObject processMap(Map<String,Object> result,  Class<? extends BaseQueryObject> qClazz) throws ReflectiveOperationException{
			//dataSourceRouting();
			BaseQueryObject obj = qClazz.newInstance();
			Field[] fieldsTo = qClazz.getDeclaredFields();
			for (String col : result.keySet()) {
				boolean match = false;
				try {
					for (int k = 0; k < fieldsTo.length; k++) {
						QueryObjCol objCol = fieldsTo[k].getAnnotation(QueryObjCol.class);
						if(objCol == null){
							continue;
						}
						if (col.equals(objCol.value())) {
							Method setter = qClazz.getDeclaredMethod(
									"set" + ReflectUtil.captureName(fieldsTo[k].getName()), fieldsTo[k].getType());
							setter.invoke(obj, result.get(col));
							match = true;
							break;
						}
					}
					if (!match) {
						obj.getExtendProperties().put(col, result.get(col));
						
					}
				} catch (Exception e) {}
			}
			return obj;
		
	}
	
	
	/**
	* @Title: processResultSet
	* @Description: 查询集反射到QO中
	* @param result
	* @param columnNames
	* @param qClazz
	* @return
	* @throws SQLException
	* @throws InstantiationException
	* @throws IllegalAccessException
	* @return BaseQueryObject
	*/ 
	public final BaseQueryObject processResultSet(ResultSet  result, List<String> columnNames, Class<? extends BaseQueryObject> qClazz) throws SQLException, InstantiationException, IllegalAccessException{
		BaseQueryObject obj = qClazz.newInstance();
		Field[] fieldsTo = qClazz.getDeclaredFields();
		for (String key : columnNames) {
			Object value = result.getObject(key);
			boolean match = false;
			try {
				for (int k = 0; k < fieldsTo.length; k++) {
					QueryObjCol objCol = fieldsTo[k].getAnnotation(QueryObjCol.class);
					if(objCol == null){
						continue;
					}
					if (key.equals(objCol.value())) {
						Method setter = qClazz.getDeclaredMethod(
								"set" + ReflectUtil.captureName(fieldsTo[k].getName()), fieldsTo[k].getType());
						setter.invoke(obj, value);
						match = true;
						break;
					}
				}
				if (!match) {
					obj.getExtendProperties().put(key, value);
					
				}
			} catch (Exception e) {}
			
		}
		return obj;
		
	}

	
	/*private void dataSourceRouting(){
		if(DataSourceType.Type.Write.equals(DBContextHolder.getContextHolder())){
			jdbcTemplate.setDataSource(dataSource);
		}else{
			DataSource source = dataSource.determineTargetDataSource();
			jdbcTemplate.setDataSource(source);
		}
	}*/

}